package com.neu.credit.creditscore.service.books.impl;

import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.neu.credit.creditscore.common.utils.*;
import com.neu.credit.creditscore.dto.res.book.BookPreOrderInfoRes;
import com.neu.credit.creditscore.dto.res.book.BookRecordRes;
import com.neu.credit.creditscore.dto.res.book.BooksListingRes;
import com.neu.credit.creditscore.dto.res.book.BooksPageListRes;
import com.neu.credit.creditscore.dto.res.hospital.ResultDetailRes;
import com.neu.credit.creditscore.entity.Transmissionjson;
import com.neu.credit.creditscore.entity.books.BookListing;
import com.neu.credit.creditscore.entity.books.BookBorrowings;
import com.neu.credit.creditscore.entity.books.BookReturnFees;
import com.neu.credit.creditscore.entity.books.BookSubBorrowings;
import com.neu.credit.creditscore.entity.books.Books;
import com.neu.credit.creditscore.entity.hospital.ExaminationItems;
import com.neu.credit.creditscore.entity.hospital.ExaminationOrders;
import com.neu.credit.creditscore.mapper.TransmissionjsonMapper;
import com.neu.credit.creditscore.mapper.books.*;
import com.neu.credit.creditscore.service.KafkaProducerService;
import com.neu.credit.creditscore.service.books.BooksService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.zachary.commonmodule.entity.MqTransmissionJson;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 图书信息表 服务实现类
 * </p>
 *
 * @author baomidou
 * @since 2025-06-14
 */
@Slf4j
@Service
public class BooksServiceImpl extends ServiceImpl<BooksMapper, Books> implements BooksService {

    @Autowired
    private BooksMapper booksMapper;

    @Autowired
    private BookListingMapper bookListingMapper;

    @Autowired
    private BookBorrowingsMapper bookBorrowingsMapper;

    @Autowired
    private BookSubBorrowingsMapper bookSubBorrowingsMapper;

    @Autowired
    private TransmissionjsonMapper  transmissionjsonMapper;
    @Autowired
    private BookReturnFeesMapper bookReturnFeesMapper;
    @Autowired
    private static final Integer ServiceType_BookBorrowing=7;
    @Autowired
    private KafkaProducerService kafkaProducerService;

    @Override
    public Result<List<Books>> getRecommendBook() {
        try {
            LambdaQueryWrapper<Books> bookQuery = new LambdaQueryWrapper<>();
            bookQuery.orderByDesc(Books::getUpdatedAt);
            List<Books> books = booksMapper.selectList(bookQuery);

            List<Books> res = new ArrayList<>();
            res.add(books.get(0));
            res.add(books.get(1));
            res.add(books.get(2));
            res.add(books.get(3));

            return Result.success(res);

        } catch (Exception e) {
            log.error("getRecommendBook has a error", e);
            return Result.error("获取失败！");
        }
    }

    @Override
    public Result<BooksPageListRes> getBooksPage(int pageNum, int pageSize, int categoryId, String title) {
        try {

            LambdaQueryWrapper<Books> booksQuery = new LambdaQueryWrapper<>();
            booksQuery.eq(categoryId != 0, Books::getCategoryId, categoryId)
                    .like(!title.equals(""), Books::getBookName, title)
                    .orderByDesc(Books::getUpdatedAt);

            Page<Books> page = new Page<>(pageNum, pageSize);
            Page<Books> booksPage = booksMapper.selectPage(page, booksQuery);
            BooksPageListRes booksPageListRes = new BooksPageListRes();
            booksPageListRes.setBooksList(booksPage.getRecords());
            booksPageListRes.setTotal(booksPage.getTotal());

            return Result.success(booksPageListRes);

        } catch (Exception e) {
            log.error("getBooksPage has a error", e);
            return Result.error("获取书籍分页失败！");
        }
    }

    @Override
    public Result<Books> getBooksDetail(int bookId) {
        try {
            Books books = booksMapper.selectById(bookId);
            return Result.success(books);
        } catch (Exception e) {
            log.error("getBooksDetail has a error", e);
            return Result.error("获取书籍详情失败！");
        }
    }

    @Override
    public Result<BooksListingRes> getBookListing(Integer currentIUserId) {
        try {

            LambdaQueryWrapper<BookListing> bookListingQuery = new LambdaQueryWrapper<>();
            bookListingQuery.eq(BookListing::getUserId, currentIUserId)
                    .eq(BookListing::getListStatus, BookListing.STATUS_NO)
                    .eq(BookListing::getDeleted, BookListing.DELETED_NO);
            List<BookListing> bookListings = bookListingMapper.selectList(bookListingQuery);
            if (CollectionUtils.isEmpty(bookListings)) {
                BooksListingRes res = new BooksListingRes();
                res.setTotalCount(0);
                res.setBooksList(Collections.emptyList());
                res.setTotalPrice("0.00");
                return Result.success(res);
            }

            int totalCount = bookListings.size();

            List<Integer> bookIds = bookListings.stream()
                    .distinct().map(BookListing::getBookId).collect(Collectors.toList());

            LambdaQueryWrapper<Books> bookQuery = new LambdaQueryWrapper<>();
            bookQuery.in(Books::getId, bookIds);
            List<Books> books = booksMapper.selectList(bookQuery);
            BigDecimal totalPrice = new BigDecimal(0);

            for (Books book : books) {
                totalPrice= totalPrice.add(book.getPrice());
            }
            // 保留两位小数，四舍五入
            totalPrice = totalPrice.setScale(2, RoundingMode.HALF_UP);

            BooksListingRes res = new BooksListingRes();
            res.setTotalCount(totalCount);
            res.setBooksList(books);
            res.setTotalPrice(totalPrice.toString());

            return Result.success(res);


        } catch (Exception e) {
            log.error("getBookListing has a error", e);
            return Result.error("获取书籍借阅清单失败！");
        }
    }

    @Override
    public Result<String> addBookListing(int bookId,Integer currentIUserId) {
        try {
            LambdaQueryWrapper<BookListing> listingQuery = new LambdaQueryWrapper<>();
            listingQuery.eq(BookListing::getUserId, currentIUserId)
                    .eq(BookListing::getBookId, bookId).eq(BookListing::getListStatus,BookListing.STATUS_NO).eq(BookListing::getDeleted,BookListing.DELETED_NO);
            Long listingCount = bookListingMapper.selectCount(listingQuery);

            if (listingCount > 0) {
                return Result.error("这本书已在您的借阅清单中，请勿重复添加");
            }
            LambdaQueryWrapper<BookBorrowings> mainQuery = new LambdaQueryWrapper<>();
            mainQuery.eq(BookBorrowings::getUserId, currentIUserId)
                    .eq(BookBorrowings::getBorrowingStatus, BookBorrowings.STATUS_USING);
            List<BookBorrowings> activeBorrowings = bookBorrowingsMapper.selectList(mainQuery);
            if (!activeBorrowings.isEmpty()) {
                List<Integer> borrowingIds = activeBorrowings.stream()
                        .map(BookBorrowings::getId)
                        .collect(Collectors.toList());

                LambdaQueryWrapper<BookSubBorrowings> subQuery = new LambdaQueryWrapper<>();
                subQuery.eq(BookSubBorrowings::getBookId, bookId)
                        .in(BookSubBorrowings::getBorrowingId, borrowingIds)
                .eq(BookSubBorrowings::getBorrowingStatus,BookSubBorrowings.STATUS_USING);

                Long count = bookSubBorrowingsMapper.selectCount(subQuery);

                if (count > 0) {
                    return Result.error("您已借阅这本书，且尚未归还");
                }
            }

            // 检查书籍库存是否充足
            Books book = booksMapper.selectById(bookId);
            if (book == null || book.getStock() <= 0) {
                return Result.error("书籍不存在或库存不足");
            }
            BookListing listing = new BookListing();
            listing.setUserId(currentIUserId);
            listing.setBookId(bookId);
            listing.setListStatus(BookListing.STATUS_NO);
            bookListingMapper.insert(listing);

            return Result.success("添加清单成功");

        } catch (Exception e) {
            log.error("addBookListing has a error", e);
            return Result.error("添加书籍清单失败！");
        }
    }

    @Override
    public Result<String> deteledBookListing(int bookId, Integer currentIUserId) {
        try {

            LambdaQueryWrapper<BookListing> listQuery = new LambdaQueryWrapper<>();
            listQuery.eq(BookListing::getUserId, currentIUserId)
                    .eq(BookListing::getBookId, bookId)
                    .eq(BookListing::getDeleted, BookListing.DELETED_NO)
                    .eq(BookListing::getListStatus,BookListing.STATUS_NO);

            BookListing listing = bookListingMapper.selectOne(listQuery);
            listing.setDeleted(BookListing.DELETED_HAS);

            bookListingMapper.updateById(listing);

            return Result.success("删除成功！");

        } catch (Exception e) {
            log.error("deteledBookListing has a error", e);
            return Result.error("删除书籍清单失败！");
        }
    }


    @Override
    public Result<BookPreOrderInfoRes> preOrderListing( Integer currentIUserId ) {
        try {



            //父借阅订单表
            BookBorrowings borrowing = new BookBorrowings();
            borrowing.setUserId(currentIUserId);
            borrowing.setBorrowDate(new Date());
            borrowing.setDueDate(DateUtils.addOneMonth(new Date()));
            borrowing.setBorrowingStatus(BookBorrowings.STATUS_PRE);
            bookBorrowingsMapper.insert(borrowing);

            //子借阅订单表
            Result<BooksListingRes> bookListing = getBookListing(currentIUserId);
            BooksListingRes data = bookListing.getData();
            List<Books> booksList = data.getBooksList();


            BigDecimal totalPrice = new BigDecimal(0);

            for (Books book : booksList) {
                BookSubBorrowings subBorrowings = new BookSubBorrowings();
                subBorrowings.setBookId(book.getId());
                subBorrowings.setBorrowingId(borrowing.getId());
                bookSubBorrowingsMapper.insert(subBorrowings);
                totalPrice.add(book.getPrice());
            }


            //费用表
            BookReturnFees fees = new BookReturnFees();
            fees.setBorrowingId(borrowing.getId());
            fees.setTotalFee(totalPrice);
            fees.setPaymentStatus(BookReturnFees.PAY_STATUS_WAIT_PAY);
            bookReturnFeesMapper.insert(fees);

            //返回给前端展示信息
            BookPreOrderInfoRes res = new BookPreOrderInfoRes();
            res.setBooksList(booksList);
            res.setTotalPrice(totalPrice.toString());
            res.setBookReturnFeesId(fees.getId());

            //todo 折扣信息

            return Result.success(res);


        } catch (Exception e) {
            log.error("preOrderListing has a error", e);
            return Result.error("预下单失败！");
        }
    }

    @Override
    public Result<String> payOrderListing(int bookReturnFeeId) {
        try {
            BookReturnFees fees = bookReturnFeesMapper.selectById(bookReturnFeeId);
            fees.setPaymentStatus(BookReturnFees.PAY_STATUS_BORROW_HAS_PAY);
            bookReturnFeesMapper.updateById(fees);

            Integer borrowingId = fees.getBorrowingId();
            BookBorrowings bookBorrowings = bookBorrowingsMapper.selectById(borrowingId);
            bookBorrowings.setBorrowingStatus(BookBorrowings.STATUS_USING);
            bookBorrowingsMapper.updateById(bookBorrowings);
            LambdaQueryWrapper<BookListing> listQuery = new LambdaQueryWrapper<>();
            listQuery.eq(BookListing::getUserId,  bookBorrowings.getUserId());
            List<BookListing> bookListing=bookListingMapper.selectList(listQuery);
            for (BookListing listing : bookListing) {
                listing.setListStatus(BookListing.STATUS_HAS);
                listing.setUpdatedAt( LocalDateTime.now());
                bookListingMapper.updateById(listing);
            }
            LambdaQueryWrapper<BookSubBorrowings> subQuery = new LambdaQueryWrapper<>();
            subQuery.eq(BookSubBorrowings::getBorrowingId, bookBorrowings.getId());
            List<BookSubBorrowings> bookSubBorrowings = bookSubBorrowingsMapper.selectList(subQuery);
            for (BookSubBorrowings sub : bookSubBorrowings){
                sub.setBorrowingStatus(BookSubBorrowings. STATUS_USING);
                bookSubBorrowingsMapper.updateById(sub);
            }
            List<Integer> bookIds = bookListing.stream()
                    .distinct().map(BookListing::getBookId).collect(Collectors.toList());

            LambdaQueryWrapper<Books> bookQuery = new LambdaQueryWrapper<>();
            bookQuery.in(Books::getId, bookIds);
            List<Books> books = booksMapper.selectList(bookQuery);
            for (Books book : books) {
                book.setBorrowedNumber(book.getBorrowedNumber() + 1);
                book.setStock(book.getStock() - 1);
                booksMapper.updateById(book);
            }
            return Result.success("支付成功！");
        } catch (Exception e) {
            log.error("payOrderListing has a error", e);
            return Result.error("支付下单失败！");
        }
    }

    @Override
    public Result<BookRecordRes>  borrowingsRecord(Integer currentIUserId ) {
        try {
            BookRecordRes res = new BookRecordRes();
            LambdaQueryWrapper<BookBorrowings> borrowQuery = new LambdaQueryWrapper<>();
            borrowQuery.eq(BookBorrowings::getUserId, currentIUserId);
            List<BookBorrowings> bookBorrowings = bookBorrowingsMapper.selectList(borrowQuery);
            if (CollectionUtils.isEmpty(bookBorrowings)) {
                res.setBookBorrowings(Collections.emptyList());
                res.setBookSubBorrowings(Collections.emptyList());
                return Result.success(res);
            }
            List<Integer> borrowingsIds = bookBorrowings.stream().distinct().map( BookBorrowings::getId).collect(Collectors.toList());
            LambdaQueryWrapper<BookSubBorrowings> subBorrowQuery = new LambdaQueryWrapper<>();
            subBorrowQuery.in(BookSubBorrowings::getBorrowingId, borrowingsIds);
            List<BookSubBorrowings> bookSubBorrowings = bookSubBorrowingsMapper.selectList(subBorrowQuery);
            if (!bookBorrowings.isEmpty()) {
                List<Integer> bookIds = bookSubBorrowings.stream().
                        map(BookSubBorrowings::getBookId).collect(Collectors.toList());
                LambdaQueryWrapper<Books> bookQuery = new LambdaQueryWrapper<>();
                bookQuery.in(Books::getId, bookIds);
                List<Books> books = booksMapper.selectList(bookQuery);
                Map<Integer, Books> bookMap = books.stream()
                        .collect(Collectors.toMap(Books::getId, book -> book));
                for (BookSubBorrowings subBorrowing : bookSubBorrowings) {
                    subBorrowing.setBookInfo(bookMap.get(subBorrowing.getBookId()));
                }
            }
            res.setBookBorrowings(bookBorrowings);
            res.setBookSubBorrowings(bookSubBorrowings);
            return Result.success( res);


        } catch (Exception e) {
            log.error("borrowingsRecord has a error", e);
            return Result.error("获取记录失败！");
        }
    }


    @Override
    public Result<String> returnBookFee( Integer bookId,Integer  borrowingsId )  {
    try{
        BookBorrowings bookBorrowings = bookBorrowingsMapper.selectById(borrowingsId);
        LambdaQueryWrapper<BookSubBorrowings> query = new LambdaQueryWrapper<>();
        query.eq(BookSubBorrowings::getBookId, bookId)
                .eq(BookSubBorrowings::getBorrowingId, borrowingsId);
        BookSubBorrowings subBorrowing = bookSubBorrowingsMapper.selectOne(query);
        subBorrowing.setBorrowingStatus(BookSubBorrowings.STATUS_USED);
        bookSubBorrowingsMapper.updateById(subBorrowing);
        LambdaQueryWrapper<BookSubBorrowings> subQuery = new LambdaQueryWrapper<>();
        subQuery.eq(BookSubBorrowings::getBorrowingId, borrowingsId).
                eq(BookSubBorrowings::getBorrowingStatus,BookSubBorrowings.STATUS_USING );
        List<BookSubBorrowings> subBorrowings = bookSubBorrowingsMapper.selectList(subQuery);
        if (subBorrowings.isEmpty()) {
            bookBorrowings.setBorrowingStatus(BookBorrowings.STATUS_USED);
            bookBorrowingsMapper.updateById(bookBorrowings);
        }
        Books  books=booksMapper.selectById(bookId);
        books.setStock(books.getStock() + 1);
        books.setBorrowedNumber(books.getBorrowedNumber() - 1);
        booksMapper.updateById(books);
    MqTransmissionJson json=new MqTransmissionJson();
    json.setUuid(bookBorrowings.getId().toString()+"bookBorrowings");
    json.setUserId(bookBorrowings.getUserId());
    json.setServiceType(ServiceType_BookBorrowing);
    json.setPaid(true);
    json.setDesc( "图书借阅信用分计算");
    json.setFinishTime(Instant.now());
    Date date = new Date();
    Date createdAt = bookBorrowings.getBorrowDate();
// 将 Date 转换为 Instant
    Instant createdAtInstant = createdAt.toInstant();
    Instant currentInstant = date.toInstant();

// 计算时间差
    Duration duration = Duration.between(createdAtInstant, currentInstant);
    Long days = 0L;
// 获取时间差（天数）
    days = duration.toDays();

// 如果不足一天不算
    if (  days<=31) {
        json.setOverdue(false);
        json.setAmount(0);
        json.setDueTime(null);
    }else {
        json.setOverdue(true);
        LambdaQueryWrapper<BookReturnFees> feeQuery = new LambdaQueryWrapper<>();
        feeQuery.eq(BookReturnFees::getBorrowingId, borrowingsId);
        BookReturnFees fees = bookReturnFeesMapper.selectOne(feeQuery);
        fees.setOverdueDays(days.intValue());
        fees.setOverdueFee(new BigDecimal(days *books.getOverdueFee().doubleValue()));
        bookReturnFeesMapper.updateById(fees);
        LambdaQueryWrapper<Transmissionjson> transmissionjsonquery = new LambdaQueryWrapper<>();
        transmissionjsonquery.eq(Transmissionjson::getUuid,  bookBorrowings.getId().toString()+"bookBorrowings");
        Transmissionjson transmissionjson=transmissionjsonMapper.selectOne(transmissionjsonquery);
        json.setDueTime(transmissionjson.getDueTime().toInstant());
        json.setAmount(  days *books.getOverdueFee().doubleValue());
    }
    if(days<=31){
        json.setOverduePeriod(0); // 0-31天为第0档

    } else  if (days <= 37) {
        json.setOverduePeriod(1); // 1-7天为第1档
    } else if (days <= 44) {
        json.setOverduePeriod(2); // 8-14天为第2档
    } else if (days <= 120) {
        json.setOverduePeriod(3); // 15天-3个月为第3档
    } else {
        json.setOverduePeriod(4); // 超过3个月归为第4档
    }
    kafkaProducerService.sendJsonMessage(json);
    return Result.success("归还成功！");
    }catch (Exception e) {
    log.error("borrowingsRecord has a error", e);
    return Result.error("归还失败！");
    }
    }

    @Component  // 确保类被Spring管理
    public class BookOverdueTask {
        @Autowired
        private BookBorrowingsMapper bookBorrowingsMapper;
        @Autowired
        private TransmissionjsonMapper transmissionjsonMapper;

        @Autowired
        private BookSubBorrowingsMapper bookSubBorrowingsMapper;

        @Autowired
        private KafkaProducerService kafkaProducerService;

        // 项目启动时执行一次
        @PostConstruct
        public void initCheck() {
            log.info("项目启动，触发图书逾期检查任务");
            checkAndUpdateOverdueBooks();
        }

        // 每天凌晨2点定期执行
        @Scheduled(cron = "0 0 2 * * ?")
        @Transactional
        public void checkAndUpdateOverdueBooks() {
            log.info("开始执行图书逾期检查任务");

            // 计算30天前的日期
            LocalDate thirtyDaysAgo = LocalDate.now().minusDays(30);
            Date overdueDate = Date.from(thirtyDaysAgo.atStartOfDay(ZoneId.systemDefault()).toInstant());

            // 查询所有未归还且借阅日期超过30天的主记录
            LambdaQueryWrapper<BookBorrowings> query = new LambdaQueryWrapper<>();
            query.le(BookBorrowings::getBorrowDate, overdueDate)
                    .eq(BookBorrowings::getBorrowingStatus, BookBorrowings.STATUS_USING);
            List<BookBorrowings> overdueBorrowings = bookBorrowingsMapper.selectList(query);

            if (!overdueBorrowings.isEmpty()) {
                // 更新主表状态为逾期
                for (BookBorrowings borrowing : overdueBorrowings) {
                    borrowing.setBorrowingStatus(BookBorrowings.STATUS_OVERDUE);
                    bookBorrowingsMapper.updateById(borrowing);
                    String currentUuid = borrowing.getId().toString()+"bookBorrowings";

                    // 检查UUID是否已存在
                    LambdaQueryWrapper<Transmissionjson> transmissionjsonquery = new LambdaQueryWrapper<>();
                    transmissionjsonquery.eq(Transmissionjson::getUuid, currentUuid);
                    Transmissionjson existing = transmissionjsonMapper.selectOne(transmissionjsonquery);

                    if (existing != null) {
                        log.info("UUID: {} 已存在，跳过发送Kafka消息", currentUuid);
                        continue;
                    }

                    // 插入记录并发送消息
                    Transmissionjson transmissionjson = new Transmissionjson();
                    transmissionjson.setUuid(currentUuid);
                    transmissionjson.setDueTime(Date.from(Instant.now()));
                    transmissionjsonMapper.insert(transmissionjson);

                    MqTransmissionJson json = new MqTransmissionJson(
                            borrowing.getId().toString()+"bookBorrowings",
                            borrowing.getUserId(),
                            ServiceType_BookBorrowing,
                            true,
                            -1,
                            true,
                            -1,
                            "图书借阅信用分计算",
                            Instant.now(),
                            null
                    );
                    kafkaProducerService.sendJsonMessage(json);
                }

                // 提取主记录ID，批量更新子表状态
                List<Integer> borrowingIds = overdueBorrowings.stream()
                        .map(BookBorrowings::getId)
                        .collect(Collectors.toList());

                BookSubBorrowings updateEntity = new BookSubBorrowings();
                updateEntity.setBorrowingStatus(BookSubBorrowings.STATUS_OVERDUE);

                LambdaQueryWrapper<BookSubBorrowings> subQuery = new LambdaQueryWrapper<>();
                subQuery.in(BookSubBorrowings::getBorrowingId, borrowingIds)
                        .eq(BookSubBorrowings::getBorrowingStatus, BookSubBorrowings.STATUS_USING);

                bookSubBorrowingsMapper.update(updateEntity, subQuery);

                log.info("逾期检查任务完成，共发现 {} 条逾期记录", overdueBorrowings.size());
            } else {
                log.info("逾期检查任务完成，未发现逾期记录");
            }
        }
    }
    @Override
    public Result<String> saveBook(Books books) {
        try {
            booksMapper.insert(books);
            return Result.success("添加成功！");

        } catch (Exception e) {
            log.error("saveBook has a error", e);
            return Result.error("添加失败！");
        }
    }

    @Override
    public Result<String> deletedBook(int bookId) {

        try {
            booksMapper.deleteById(bookId);
            return Result.success("删除失败！");
        } catch (Exception e) {
            log.error("deletedBook has a error", e);
            return Result.error("删除失败！");
        }
    }

    @Override
    public Result<String> updateBook(Books books) {
        try {
            booksMapper.updateById(books);
            return Result.success("修改成功！");
        } catch (Exception e) {
            log.error("updateBook has a error", e);
            return Result.error("修改失败！");
        }


    }
}